package com.hayukleung.voiceserver;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import com.hayukleung.util.Constants;

public class Server extends Thread
{
  private Socket socket;

  // manager login info
  static HashMap<String, String> userMap = new HashMap<String, String>();
  static
  {
    // username - password list
    userMap.put("user00", "00");
    userMap.put("user01", "01");
    userMap.put("user02", "02");
    userMap.put("user03", "03");
    userMap.put("user04", "04");
    userMap.put("user05", "05");
  }

  // manager pool
  static HashMap<String, Pool> pools = new HashMap<String, Pool>();

  public static Set<String> ipSet = new HashSet<String>();

  // constructor
  public Server(Socket socket)
  {
    this.socket = socket;
    File baseDir = new File(Constants.BASE_DIR);
    if (!baseDir.exists())
    {
      baseDir.mkdirs();
    }
  }

  @Override
  public void run()
  {
    super.run();
    try
    {
      InputStream inputStream = socket.getInputStream();
      OutputStream outputStream = socket.getOutputStream();

      byte[] cmdByte = new byte[100];
      inputStream.read(cmdByte);

      String cmd = new String(cmdByte).trim();

      if (cmd.startsWith(Constants.REQ_LOGIN))
      { // login process ======================================================
        // login,username,password
        String[] strings = cmd.split(Constants.COMMA);
        String username = strings[1];
        String password = strings[2];
        try
        {
          if (userMap.get(username).equals(password))
          { // login success
            outputStream.write(Constants.REPLY_OK.getBytes());
            outputStream.flush();
            // once login success, add IP to the set
            ipSet.add(socket.getInetAddress().getHostAddress());
            return;
          }
          throw new Exception();
        }
        catch (Exception userNotExistException)
        {
          outputStream.write(Constants.REPLY_ERROR.getBytes());
          outputStream.flush();
        }
      }
      else if (cmd.startsWith(Constants.REQ_DOWNLOAD))
      { // download process ===================================================
        // received client download request: [get,filename]
        String[] strings = cmd.split(Constants.COMMA);
        String filename = strings[1];

        try
        {
          File file = new File(Constants.BASE_DIR, filename);
          if (file.exists())
          {
          	// reply client download request: [ok,filesize]
            String request = Constants.REPLY_OK + Constants.COMMA + file.length();
            outputStream.write(request.getBytes());
            outputStream.flush();
            System.out.println(request);
            byte[] reply = new byte[10];
            inputStream.read(reply);
            System.out.println(new String(reply));
            FileInputStream fileInputStream = new FileInputStream(file);
            int len = 0;
            byte[] temp = new byte[1024];
            while (-1 != (len = fileInputStream.read(temp)))
            { // read file and send out byte by byte
              outputStream.write(temp, 0, len);
              outputStream.flush();
            }
            fileInputStream.close();
            return;
          }
          throw new Exception();
        }
        catch (Exception e)
        {
          e.printStackTrace();
          outputStream.write(Constants.REPLY_ERROR.getBytes());
          outputStream.flush();
        }
      }
      else if (cmd.startsWith(Constants.REQ_UPLOAD))
      { // upload process =====================================================
        // upload,filesize,username
        String[] strings = cmd.split(Constants.COMMA);
        long filesize = Long.parseLong(strings[1]);
        String username = strings[2];
        outputStream.write(Constants.REPLY_OK.getBytes());
        outputStream.flush();
        String filename = (new Date().getTime()) + "R" + ((int) (Math.random() * 100000)) + ".amr";
        File file = new File(Constants.BASE_DIR, filename);
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        byte[] temp = new byte[1024];
        int len = 0;
        long totalsize = 0;
        while (-1 != (len = inputStream.read(temp)))
        {
          totalsize += len;
          fileOutputStream.write(temp, 0, len);
          if (totalsize >= filesize)
          {
            break;
          }
        }
        // upload finish
        fileOutputStream.close();
        // one voice message one pool
        Pool pool = new Pool();
        pools.put(pool.id, pool);

        // broadcast token: [username,filename,poolid]
        pool.message = username + Constants.COMMA + file.getName();
        // copy IP from ipSet to pool.ipSet
        for (String ip : ipSet)
        {
          if (ip.equalsIgnoreCase(socket.getInetAddress().getHostAddress()))
          { // if IP equals with current connecting IP address, skip it
            continue;
          }
          pool.ipSet.add(ip);
        }

        pool.start();
      }
    }
    catch (Exception streamException)
    {
      streamException.printStackTrace();
    }
    finally
    {
      try
      {
        socket.close();
      }
      catch (Exception closeException)
      {
        closeException.printStackTrace();
      }
    }

  }

  // open server
  public static void openServer() throws Exception
  {
    ServerSocket serverSocket = new ServerSocket(Constants.SERVER_TCP_PORT_INT);

    while (true)
    {
      new Server(serverSocket.accept()).start();
    }
  }

  // close server
  public static void closeServer()
  {

  }

}
